#include "Polygon.h"

//in NDC
bool IsClockwise(const SVec2& P1,const SVec2& P2,const SVec2& P3)
{
   return (P3-P2).CrossProduct(P1-P2)>0;
}

bool IsInTriangle(const SVec2& Point , const SVec2& P1,const SVec2& P2,const SVec2& P3)
{
    //reference https://blog.csdn.net/yingyujianmo/article/details/49663695
    double U=(P1.X * P3.Y -P3.X * P1.Y ) /(P2.X * P3.Y -P3.X * P2.Y );
    double V=(P1.X * P2.Y -P2.X * P1.Y ) /(P3.X * P2.Y -P2.X * P3.Y );
    
    return U>0 && V>0 && (U+V)<1 ;
}


CPolygon::CPolygon(TVector<SVertex2D> InVertice,TSharedObjectPtr<RMaterial> InMaterial)
:Vertice(InVertice),Material(InMaterial)
{

}

CPolygon::CPolygon(TVector<SVec2> InPosition,TVector<SVec2> InUV,TSharedObjectPtr<RMaterial> InMaterial)
:Material(InMaterial)
{
    assert(InPosition.Num()==InUV.Num());

    for(uint64_t VertexIndex=0;VertexIndex<InPosition.Num();VertexIndex++)
    {
        Vertice.Emplace(InPosition[VertexIndex],InUV[VertexIndex]);
    }

}

TVector<CTriangle2D> CPolygon::ToTriangles()
{
    TVector<CTriangle2D> Ret;
    
    auto AllVertice=this->Vertice;

    while(AllVertice.Num()>3)
    {
        for(uint64_t VertexIndex=0;VertexIndex<AllVertice.Num();VertexIndex++)
        {
            if(!IsClockwise(AllVertice[VertexIndex].Position,
                        AllVertice[VertexIndex+1].Position,
                        AllVertice[VertexIndex+2].Position))
            {
                continue;
            }

            bool HaveAnyOtherVertexInTriangle=false;
            for(uint64_t OtherVertexIndex=0;OtherVertexIndex<AllVertice.Num();OtherVertexIndex++)
            {
                if(OtherVertexIndex==VertexIndex
                    ||  OtherVertexIndex==VertexIndex+1
                    ||  OtherVertexIndex==VertexIndex+2
                )
                {
                    continue;
                }
                if(
                    IsInTriangle(AllVertice[OtherVertexIndex].Position,
                            AllVertice[VertexIndex].Position,
                            AllVertice[VertexIndex+1].Position,
                            AllVertice[VertexIndex+2].Position)
                )
                {
                    HaveAnyOtherVertexInTriangle=true;
                    break;
                }
            }

            if(HaveAnyOtherVertexInTriangle) 
            {
                continue;
            }           

            Ret.Add(CTriangle2D(AllVertice[VertexIndex],
                                AllVertice[VertexIndex+1],
                                AllVertice[VertexIndex+2]
                                ));
            
            AllVertice.RemoveAt(VertexIndex);
            break;
        }
    }

    if(AllVertice.Num()==3)
    {
        Ret.Add(CTriangle2D(AllVertice[0],
            AllVertice[1],
            AllVertice[2]
            ));
    }

    return Ret;

}

TVector<CTriangle2D> CPolygon::CreatePolygonTriangles(TVector<SVec2> InVertice,TVector<SVec2> InUV)
{
    TVector<CTriangle2D> Ret;
    
    TVector<SVertex2D> Vertice;
    for(uint64_t VertexIndex=0;VertexIndex<InVertice.Num();VertexIndex++)
    {
        Vertice.Emplace(InVertice[VertexIndex],InUV[VertexIndex]);
    }

    auto AllVertice=Vertice;

    while(AllVertice.Num()>3)
    {
        for(uint64_t VertexIndex=0;VertexIndex<AllVertice.Num();VertexIndex++)
        {
            if(!IsClockwise(AllVertice[VertexIndex].Position,
                        AllVertice[VertexIndex+1].Position,
                        AllVertice[VertexIndex+2].Position))
            {
                continue;
            }

            bool HaveAnyOtherVertexInTriangle=false;
            for(uint64_t OtherVertexIndex=0;OtherVertexIndex<AllVertice.Num();OtherVertexIndex++)
            {
                if(OtherVertexIndex==VertexIndex
                    ||  OtherVertexIndex==VertexIndex+1
                    ||  OtherVertexIndex==VertexIndex+2
                )
                {
                    continue;
                }
                if(
                    IsInTriangle(AllVertice[OtherVertexIndex].Position,
                            AllVertice[VertexIndex].Position,
                            AllVertice[VertexIndex+1].Position,
                            AllVertice[VertexIndex+2].Position)
                )
                {
                    HaveAnyOtherVertexInTriangle=true;
                    break;
                }
            }

            if(HaveAnyOtherVertexInTriangle) 
            {
                continue;
            }           

            Ret.Add(CTriangle2D(AllVertice[VertexIndex],
                                AllVertice[VertexIndex+1],
                                AllVertice[VertexIndex+2]
                                ));
            
            AllVertice.RemoveAt(VertexIndex);
            break;
        }
    }

    if(AllVertice.Num()==3)
    {
        Ret.Add(CTriangle2D(AllVertice[0],
            AllVertice[1],
            AllVertice[2]
            ));
    }

    return Ret;

}